package com.fuyd.pms.background.service.account;

import com.fuyd.pms.entity.account.LocalAuth;
import com.fuyd.pms.entity.account.MerchantUser;
import com.fuyd.pms.utils.Encodes;
import org.apache.commons.codec.DecoderException;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * shiro认证相关
 * Created by fuyongde on 2015/12/26.
 */
@Component
public class ShiroDbRealm extends AuthorizingRealm {

    /**
     * 账户管理的service
     **/
    private AccountService accountService;

    @Autowired
    public void setAccountService(AccountService accountService) {
        this.accountService = accountService;
    }

    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     * 授权操作，决定那些角色可以使用那些资源
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        MerchantUser shiroUser = (MerchantUser) principalCollection.getPrimaryPrincipal();
        LocalAuth localAuth = accountService.findLocalAuthByUsername(shiroUser.getUsername());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(localAuth.getMerchantUser().getRoleList());
        return info;
    }

    /**
     * 认证回调函数
     * 认证操作，判断一个请求是否被允许进入系统
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        LocalAuth localAuth = accountService.findLocalAuthByUsername(usernamePasswordToken.getUsername());
        MerchantUser merchantUser = localAuth.getMerchantUser();

        if (merchantUser == null) {
            //用户不存在
            throw new UnknownAccountException();
        } else if (merchantUser.getLocked()) {
            //用户被锁定
            throw new LockedAccountException();
        } else {
            byte[] salt = new byte[0];
            try {
                salt = Encodes.decodeHex(localAuth.getSalt());
            } catch (DecoderException e) {
                e.printStackTrace();
            }
            return new SimpleAuthenticationInfo(merchantUser, localAuth.getPassword(), ByteSource.Util.bytes(salt), getName());
        }
    }

    /**
     * 设定Password校验的Hash算法与迭代次数.
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(AccountService.HASH_ALGORITHM);
        matcher.setHashIterations(AccountService.HASH_INTERATIONS);

        setCredentialsMatcher(matcher);
    }
}
